/**
 *  \file   xmac_tx.c
 *  \author Miora ANDRIAMANOHARISOA, Loic MINGHETTI
 *  \date   PFE 2011
 **/

#include "include.h"

tx_states tx_state = inactive;

// packet id
unsigned int node_last_packet_id = 0;

// count transmit with no response
int rx_fail_count = 0;

// pending data queue for tx
static temp_data tx_data[10];
static int tx_data_last_tx_pos = 0;
static int tx_data_last_added_pos = 0;

int xmac_tx_append_lock = 0;
int xmac_tx_append(temp_data data) {
	if (xmac_tx_append_lock) return -1;
	tx_data_last_added_pos = (tx_data_last_added_pos+1)%CONF_TX_QUEUE;
	
	if ( tx_data_last_added_pos == tx_data_last_tx_pos) {
		printf("\r\n(!) TX queue overflow. Oldest packet discarded\r\n");
		tx_data_last_tx_pos = (tx_data_last_tx_pos+1)%CONF_TX_QUEUE;
	}
	
	tx_data[tx_data_last_added_pos] = data;
	return 0;
}

void tx(char* msg, int size) {
	led_green_on();
	timer_watch(&TIMER_LED, led_green_off, 3);
	cc2500_utx(msg, size);
	//LPM(1); // one tick needed for msg to be properly sent
	if (verbocity >= 2) {
		printf("\r\n        Sent: size=%d, msg=", size);
		int i;
		for(i = 0; i < size ;i++ ){
			printf("%x ", (uint8_t) msg[i]);
		}
	}
}

PT_THREAD(thread_xmac_tx(struct pt *pt)) {
    PT_BEGIN(pt);
    
    static uint8_t preambule_counter;
    static uint8_t new_hop_count;
    static msg_preambule preambule;
    static msg_preambule_ack * p_preambule_ack;
    static msg_data data;
    static msg_data_ack * p_data_ack;
    static int i;

    while(1) {
    	
    	tx_state = inactive;
    	
    	PT_WAIT_UNTIL(pt, tx_data_last_tx_pos != tx_data_last_added_pos && node_id > 0);
    	tx_state = pending;
    	if (verbocity) printf("\r\nTX : tx_state -> pending : messages waiting to be sent");
    	
		PT_WAIT_UNTIL(pt, tx_state == active && node_id > 0);
		preambule.source = node_id;
		preambule.type = MSG_TYPE_PREAMBULE;
		switch (rx_fail_count) {
			case 0 : preambule.destination_hop_count = node_hop_count - 1; break; // close node only
			case 1 : preambule.destination_hop_count = node_hop_count; break; // include same level nodes
			case 2 : preambule.destination_hop_count = node_hop_count + 1; break; // include parent nodes
			default : preambule.destination_hop_count = 0xFF; break; // any node will reply (SOS!)
		}
		// start timer
		TIMER_PREAMBULE = 0;
		for (preambule_counter = CONF_NUM_PREAMBULES; preambule_counter > 0; preambule_counter--) {
			// send preambule
			if (verbocity) printf("\r\nTX : Sending Preambule #%d", preambule_counter);

			preambule.count_down = preambule_counter;
			// start counter
			tx ((char *)&preambule, MSG_SIZE_PREAMBULE);
			PT_YIELD(pt);
			// listen for preambule ack or timeout
			xmac_listen_start();
			TIMER_TX = 0; // response timeout
			PT_WAIT_UNTIL(pt, TIMER_TX >= CONF_RESPONSE_TIMEOUT || rx_buffer_flag);
			if (rx_buffer_flag) {
				TIMER_TX = 0; // send delay
				if (rx_buffer_msg[2] != MSG_TYPE_PREAMBULE_ACK) {
					if (verbocity) printf("\r\nTX : Received invalid message while expecting preambule ack (wrong msg type %d)", rx_buffer_msg[2]);
					PT_RESTART(pt);
				}
				p_preambule_ack = (msg_preambule_ack *) rx_buffer_msg;
				if ((*p_preambule_ack).destination != node_id)  {
					if (verbocity) printf("\r\nTX : Received invalid message while expecting preambule ack (wrong destination %d instead of %d)", (*p_preambule_ack).destination, node_id);
					PT_RESTART(pt);
				}
				new_hop_count = (*p_preambule_ack).source_hop_count + 1;
				if (verbocity) printf("\r\nTX : Received valid preambule ack");
				rx_fail_count = 0;

				// send data
				xmac_tx_append_lock = 1;
				data.source = node_id;
				data.type = MSG_TYPE_DATA;
				data.destination = (*p_preambule_ack).source;
				data.packet_id = ++node_last_packet_id;
				i = -1;
				while ( (tx_data_last_tx_pos+i+1)%CONF_TX_QUEUE != tx_data_last_added_pos) {
					i++;
					data.data[i] = tx_data[ (tx_data_last_tx_pos+i+1)%CONF_TX_QUEUE ];
				}
				data.data_length = (i+1)*MSG_SIZE_DATA_TEMP;				
				
				if (verbocity) printf("\r\nTX : Sending data msg");
				PT_WAIT_UNTIL(pt, TIMER_TX >= CONF_RADIO_SWITCH_DELAY); // give time for received to swtich tx->rx
				tx ((char *)&data, (MSG_SIZE_DATA_HEADER+(i+1)*MSG_SIZE_DATA_TEMP));
				PT_YIELD(pt);
				
				// listen for data ack
				xmac_listen_start();
				TIMER_TX = 0;
				PT_WAIT_UNTIL(pt, TIMER_TX >= CONF_RESPONSE_TIMEOUT || rx_buffer_flag);
				if (!rx_buffer_flag) {
					xmac_listen_stop();
					if (verbocity) printf("\r\nTX : Timeout while expecting data ack");
					PT_RESTART(pt);
				} else if (rx_buffer_msg[2] != MSG_TYPE_DATA_ACK) { // if invalid msg received
					if (verbocity) printf("\r\nTX : Received invalid message while expecting data ack (wrong msg type %d)", rx_buffer_msg[2]);
					PT_RESTART(pt);
				}
				p_data_ack = (msg_data_ack *) rx_buffer_msg;
				if ((*p_data_ack).destination != node_id || (*p_data_ack).packet_id != node_last_packet_id)  {
					if (verbocity) printf("\r\nTX : Received invalid message while expecting data (wrong destination or packet id)");
					PT_RESTART(pt);
				}
				
				if (verbocity) printf("\r\nTX : Received valid data ack");
				
				tx_data_last_tx_pos = tx_data_last_added_pos;
				if (verbocity) printf("\r\nTX : Data sent successfully");
				xmac_tx_append_lock = 0;
				if (new_hop_count != node_hop_count) {
					if (verbocity) printf("\r\nTX : New hop count is %d (previous %d)", new_hop_count, node_hop_count);
					node_hop_count = new_hop_count;
					flash_save_config();
				}
				PT_RESTART(pt);
				
			}
			// no response, so run premabule again
			xmac_listen_stop();
			PT_WAIT_UNTIL(pt, TIMER_PREAMBULE >= CONF_PREAMBULE_PERIOD);
			TIMER_PREAMBULE -= CONF_PREAMBULE_PERIOD;
			
		}
		
		// failed getting a response for preambule sequence, restart with different hop count requirement
		rx_fail_count++;
		if (verbocity) printf("\r\nTX : Failed getting a response for preambule, restart with different hop count (failure #%d)", rx_fail_count);
		//PT_RESTART(pt);
    	
    }

    PT_END(pt);
}

